
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
//#include <string.h>

#ifdef WIN32

#include <windows.h>
#include <winsock.h>

#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)


#define _fail(er) *Qplayers = -1; Qmaxplayers = (err); closeocket(Socket); return(false)

#else

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <strings.h>

#define SD_BOTH 2

#define _fail(er) *Qplayers = -1; *Qmaxplayers = (er); shutdown(sockfd, SD_BOTH); close(sockfd); return(false)

#endif


#ifdef WIN32

int timeout_recvfrom(IN SOCKET s, __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf, IN int len, IN int flags, __out_bcount(*fromlen) struct sockaddr FAR * from,IN OUT int FAR * fromlen,int timeoutinseconds)
{
	fd_set socks;
	timeval t;
	FD_ZERO(&socks);
	FD_SET(s,&socks);
	t.tv_sec = timeoutinseconds;
	if (select(s + 1, &socks, NULL, NULL, &t)) return recvfrom(s, buf, len, flags, from, fromlen);
	else return SOCKET_ERROR;
}

#else

int timeout_recvfrom(int s, char * buf, int len, int flags, struct sockaddr * from, socklen_t * fromlen, int timeoutinseconds)
{
	fd_set socks;
	timeval t;
	FD_ZERO(&socks);
	FD_SET(s,&socks);
	t.tv_sec = timeoutinseconds;
	if (select(s + 1, &socks, NULL, NULL, &t)) return recvfrom(s, (char *)buf, len, flags, (struct sockaddr *)from, (socklen_t *)fromlen);
	else return -1;
}
#endif

bool getquery_p(char sIP[],int iPort, int *Qplayers, int *Qmaxplayers)
{ 
	char QPacket[11], Buf[64];

	#ifdef WIN32 // windows
	SOCKET Socket2;
	SOCKADDR_IN addr2;

	WSADATA wsa;
    struct hostent *hp;


	int rc = WSAStartup(MAKEWORD(2, 0), &wsa);

	if(rc == SOCKET_ERROR)
	{
		*Qplayers = -1;
		*Qmaxplayers = -3;
		return false;
	}


    Socket2 = socket(AF_INET, SOCK_DGRAM, 0);
    if(Socket2 == INVALID_SOCKET)
	{
		closesocket(Socket2);
		*Qplayers = -1;
		*Qmaxplayers = -4;
		return false;
	}
    hp = gethostbyname(sIP);
    if (hp == 0)
	{
		closesocket(Socket2);
		*Qplayers = -1;
		*Qmaxplayers = -1;
		return false;
	}


	addr2.sin_addr.s_addr = inet_addr( sIP );

	#else // linux

	int sockfd, rc;
    struct hostent *hp;
	struct sockaddr_in addr2;


	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    hp = gethostbyname(sIP);
    if (!hp)
	{
	  /*
		*Qplayers = -1;
		*Qmaxplayers = -1;
		closesocket(sockfd);
		return false;
		*/
	  _fail(-1);
	}

    //strncpy(&addr2.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
	bcopy((char *)hp->h_addr,
		(char *)&addr2.sin_addr.s_addr,
		hp->h_length);

	#endif

    addr2.sin_port        = htons(iPort);
    addr2.sin_family      = AF_INET;

    int iIp[4];
    sscanf(sIP, "%i.%i.%i.%i", &iIp[0], &iIp[1],&iIp[2],&iIp[3]);
    QPacket[0] = 'S';
    QPacket[1] = 'A';
    QPacket[2] = 'M';
    QPacket[3] = 'P';
    for(int i = 0; i<4;i++) QPacket[i+4] = (char)iIp[i];
    QPacket[8] = (char)(iPort & 0xFF);
    QPacket[9] = (char)(iPort >> 8 & 0xFF);
    QPacket[10] = 'i';
  //QPacket[11] = '\0';

	#ifdef WIN32
	sendto(Socket2,(char*)QPacket,sizeof(QPacket),0,(struct sockaddr *) &addr2,sizeof(addr2));

    SOCKADDR_IN remoteAddr;
    int remoteAddrLen=sizeof(SOCKADDR_IN);
    rc = timeout_recvfrom(Socket2,(char*)Buf, 64, 0, (SOCKADDR*)&remoteAddr,&remoteAddrLen,1);

    if(rc==SOCKET_ERROR)
	{
		closesocket(Socket2);
		*Qplayers = -1;
		*Qmaxplayers = -2;
		return false;
	}
	else if(rc < 15)
	{
		closesocket(Socket2);
		*Qplayers = -1;
		*Qmaxplayers = -5;
		return false;
	}
	Buf[rc] = '\0';
	#else
	socklen_t addr2_len = sizeof(addr2);
    sendto(sockfd,(char*)QPacket,sizeof(QPacket),0,(struct sockaddr *) &addr2,addr2_len);

    struct sockaddr_in remoteAddr;
    int remoteAddrLen=sizeof(struct sockaddr_in);
    rc = timeout_recvfrom(sockfd,(char*)Buf, sizeof(Buf), 0, (struct sockaddr*)&remoteAddr,(socklen_t*)&remoteAddrLen, 1);

    if(rc < 1)
	{
		//closesocket(sockfd);
		/*
		*Qplayers = -1;
		*Qmaxplayers = -2;
		close(sockfd);
		return false;
		*/
		_fail(-2);
	}
    //Buf[rc]='\0';

	#endif
   // Qpw = Buf[11];
	*Qplayers = (Buf[12]) + (Buf[13] << 8);
	*Qmaxplayers =(Buf[14])+ (Buf[15] << 8);
	#ifdef WIN32
	closesocket(Socket2);
	#else
	shutdown(sockfd, SD_BOTH);
	close(sockfd);
	#endif
    return true;
}

